package com.shell.guard.config.oauth;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

import com.shell.guard.security.CustomAuthorizationTokenServices;
import com.shell.guard.security.CustomTokenEnhancer;

@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
	
	@Autowired
	private AuthenticationManager authenticationManager;
	@Autowired
	private DataSource dataSource;
	@Autowired
	private RedisConnectionFactory redisConnectionFactory;
	@Autowired
	private WebResponseExceptionTranslator webResponseExceptionTranslator;

	@Bean
	public JdbcClientDetailsService clientDetailsService(DataSource dataSource) {
		return new JdbcClientDetailsService(dataSource);
	}

	@Bean
	public RedisTokenStore tokenStore(RedisConnectionFactory connectionFactory) {
		return new RedisTokenStore(connectionFactory);
	}

	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
	}

	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.withClientDetails(clientDetailsService(this.dataSource));
	}

	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints.authenticationManager(this.authenticationManager).tokenStore(tokenStore(this.redisConnectionFactory))
				.tokenServices(authorizationServerTokenServices()).accessTokenConverter(accessTokenConverter())
				.exceptionTranslator(this.webResponseExceptionTranslator);
	}

	@Bean
	public JwtAccessTokenConverter accessTokenConverter() {
		JwtAccessTokenConverter converter = new CustomTokenEnhancer();
		converter.setSigningKey("secret");
		return converter;
	}

	@Bean
	public AuthorizationServerTokenServices authorizationServerTokenServices() {
		CustomAuthorizationTokenServices customTokenServices = new CustomAuthorizationTokenServices();
		customTokenServices.setTokenStore(tokenStore(this.redisConnectionFactory));
		customTokenServices.setSupportRefreshToken(true);
		customTokenServices.setReuseRefreshToken(true);
		customTokenServices.setClientDetailsService(clientDetailsService(this.dataSource));
		customTokenServices.setTokenEnhancer(accessTokenConverter());
		return customTokenServices;
	}
}
